using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Xml.XPath;
using System.Configuration;
using System.Xml;
using System.Text.RegularExpressions;
using System.Reflection;

namespace Common
{
    [DefaultProperty("Text")]
    [ToolboxData("<{0}:SiteMapPath runat=server></{0}:SiteMapPath>")]
    public class SiteMapPath : WebControl
    {
        [Bindable(true)]
        [Category("Appearance")]
        [DefaultValue("")]
        [Localizable(true)]
        public string Text
        {
            get
            {
                return GetPath(HttpContext.Current.Request.Url.Host, HttpContext.Current.Request.RawUrl);
            }
        }

        protected override void RenderContents(HtmlTextWriter output)
        {
            output.Write(Text);
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
        }
        protected override object SaveViewState()
        {
            return null;
        }
        static XmlDocument doc;
        string GetPagePropertyValue(string propertyName)
        {
            return Page.GetType().GetProperty(propertyName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).GetValue(Page, null).ToString();
        }
        string MakeLink(XmlNode node)
        {
            string curTitle;
            string curLink;
            if (node.Attributes["dynamic"].Value != "false")
            {
                try
                {
                    curTitle = GetPagePropertyValue(node.Attributes["pageProperty"].Value);
                    curLink = string.Format(node.Attributes["DefaultUrlFormat"].Value, GetPagePropertyValue(node.Attributes["pageValueProperty"].Value));

                }
                catch
                {
                    curTitle = node.Attributes["title"].Value;
                    curLink = node.Attributes["url"].Value;
                }
            }
            else
            {
                curTitle = node.Attributes["title"].Value;
                curLink = node.Attributes["url"].Value;
            }
            return string.Format(ConfigurationManager.AppSettings["siteMapFormat"], curLink, curTitle);
        }
        static void PreloadSiteMap()
        {
            if (doc == null)
            {
                lock (typeof(SiteMapPath))
                {
                    doc = new XmlDocument();
                    string siteMapUrl = ConfigurationManager.AppSettings["siteMap"];
                    if (!string.IsNullOrEmpty(siteMapUrl))
                    {
                        doc.Load(siteMapUrl);
                    }
                }
            }
        }
        string GetPath(string host, string rawUrl)
        {
            string text = HttpContext.Current.Cache[string.Format("siteMap_{0}_{1}", host, rawUrl)] as string;
            if (string.IsNullOrEmpty(text))
            {
                PreloadSiteMap();
                XmlNodeList nodes = doc.SelectNodes(string.Format("//path[@host='{0}']", host));
                StringBuilder sb = new StringBuilder(ConfigurationManager.AppSettings["siteMapStart"]);
                int pos = sb.Length;
                foreach (XmlNode node in nodes)
                {
                    string pattern = @"\A" + node.Attributes["rawUrl"].Value + @"\Z";
                    if (Regex.IsMatch(rawUrl, pattern, RegexOptions.IgnoreCase | RegexOptions.Singleline))
                    {
                        string curTitle;
                        if (node.Attributes["dynamic"].Value != "false")
                        {
                            try
                            {
                                curTitle = Page.GetType().GetProperty(node.Attributes["pageProperty"].Value, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).GetValue(Page, null).ToString();
                            }
                            catch (Exception ex)
                            {
                                curTitle = node.Attributes["title"].Value + "(error:" + ex.Message + ")";
                            }
                        }
                        else
                        {
                            curTitle = node.Attributes["title"].Value;
                        }
                        sb.Insert(pos, curTitle);
                        XmlNode pNode = node;
                        while (pNode.ParentNode != null && pNode.ParentNode.NodeType != XmlNodeType.Document)
                        {
                            pNode = pNode.ParentNode;
                            sb.Insert(pos, MakeLink(pNode));
                        }
                        break;
                    }
                }
                text = sb.ToString();
                HttpContext.Current.Cache.Add(string.Format("siteMap_{0}_{1}", host, rawUrl), text, null, DateTime.Now.AddHours(3), TimeSpan.Zero, System.Web.Caching.CacheItemPriority.Normal, null);
            }
            return text;
        }
    }
}
